﻿using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows;
using System.Windows.Media;
using System.Windows.Threading;

namespace BeerManagementSystem
{
    public class Controller
    {   //Instanzen
        private ICardReader _cardReader;
        private Backend _backend;
        private CheckIn _checkIn; // GUI
        private UriConnector _uriConnector;
        private UserProfile _userProfile;
        private BeerdocterProfile _beerdocterProfile;
        private User _inviterUser;
        private WebConnector _webConnector;
        private BeerboxUpdater _beerboxUpdater;
        //Variables
        private DispatcherTimer _cardTimer;
        //Transaktionstyp 1 = zt, 2 = t, 3 = z
        private byte _transactionType = 1;
        //Getränketyp der nächsten Transaktion
        private Drink _drink;
        //Speichert die Card ID der aktuellen Assigning card
        private int _overwriteCardId;
        //User der letzten Transaction
        User _currentUser;
        //Gastuser
        private User _guestUser;
        //Setzt den GameCdMode
        private static bool _gameCdPlayingMode;
        private User _currentGameCdPlayer;
        // Setzt Einladenmodus
        public bool InviteMode = false;
        //Setzt den GuestAssignmode
        private bool _guestAssignMode;
        // Nr des angezeigten Beerdocters (letzte = 0)
        private int _docterNumber;
        private List<User> _inviterList;
        // Abfrage ob neuer User erstellt werden soll
        public bool SuggestionCreateUser;
        private EventHandler _initGameCd;
        private EventHandler<GameCdEventArgs> _startGameCd;
        private EventHandler _lostGameCdEventHandler;
#region Singleton
        // Instanz dieser Klasse für singleton
        private static Controller _controller;
        public static Controller Instance
        {
            get
            {
                return _controller ?? (_controller = new Controller());
            }
        }

#endregion
        private Controller()
        {
            _backend = new Backend();
            _uriConnector = UriConnector.Instance;
            _webConnector = new WebConnector();
            _currentUser = _backend.GetCurrentUser();
            _drink = Drink.Beer;
            

            
            //Initialisiere Kartenleser
            _cardReader = new MagTekCardReader();
            _cardTimer = new DispatcherTimer {Interval = TimeSpan.FromSeconds(1)};

            #region Cardreader Event handler

            _cardReader.CardRead += CardReaderOnCardRead;
            _cardReader.CardInvalid += CardReaderOnCardInvalid;
            _cardReader.BarrelReset += CardReaderOnBarrelReset;
            _cardReader.ResetLastTransaction += CardReaderOnResetLastTransaction;
            _cardReader.Einladen += CardReaderOnEinladen;
            _cardTimer.Tick += CardTimerOnTick;
            #endregion
            _cardReader.AcceptNextCard();
        }
       

        private void CardTimerOnTick(object sender, EventArgs eventArgs)
        {
            _cardTimer.Stop();
            _cardReader.AcceptNextCard();
            _checkIn.ShowTransp();
        }

        public bool SuggestionOverideAssignment { get; set; }

        public static bool GameCdPlayingMode
        {
            get { return _gameCdPlayingMode; }
            set { _gameCdPlayingMode = value; }
        }

        private void EnableInviterMode()
        {
            _transactionType = 3;
            _checkIn.InitializeInviter(); // Initialisiert den Inviter-Tab
            _inviterList = new List<User>();
            InviteMode = true;
        }

        public void DisableInviterMode()
        {
            foreach (var user in _inviterList)
            {
                _backend.WriteTransaction(user, 2, _drink);
                _backend.WriteTransaction(_inviterUser, 3, _drink);
            }
            _checkIn.DeleteSelectedTabItem(_checkIn.GetTabItem("Inviter"));
            _checkIn.FinalizeInviter();
            _transactionType = 1;
            _drink = Drink.Beer;
            InviteMode = false;
            UpdateStats();
        }

        private void UpdateStats()
        {
            Ranking ranking = _backend.GetRanking(15, 10, 10);
            _checkIn.UpdateRanking(ranking);

            if(Properties.Settings.Default.WebConnectorStatus)_webConnector.UpdateBmsRanking(Properties.Settings.Default.BarrelFillnessStatus, ranking);

            //_webConnector.UpdateUserProfiles();

            // Statistik initialisieren

            _checkIn.SetBarrelStatus(Properties.Settings.Default.BarrelFillnessStatus);
            
            //User Profil aktualisieren
            _userProfile = new UserProfile(_currentUser)
                {
                    BitmapImage = _uriConnector.GetProfileImage(_currentUser),
                    CurrentRank = _backend.GetUserRank(_currentUser)
                };
            _checkIn.UpdateUserProfile(_userProfile, _backend.GetLastTransaction(_currentUser));

            // BeerDocter akutalisieren
            _beerdocterProfile = new BeerdocterProfile(_backend.GetBeerDocterProfile(_docterNumber))
                {
                    BitmapImage = _uriConnector.GetProfileImage(_backend.GetBeerDocterProfile(_docterNumber))
                };
            _checkIn.UpdateBeerDocterProfile(_beerdocterProfile);

            //Updated die Fehlbetrag aus der Exceltabelle Beerbill in die Userdatenbank AccountBeerbill
            //UpdateUserAccountBeerbill();

            
        }

        public void EnableGameCountdown()
        {
            
        }

        private void CardReaderOnEinladen(object sender, EventArgs eventArgs)
        {
            StartInviteMode();
        }

        private void CardReaderOnResetLastTransaction(object sender, EventArgs eventArgs)
        {
            _backend.DeleteLastTransaction();
            
        }


        private void CardReaderOnBarrelReset(object sender, EventArgs eventArgs)
        {
            throw new NotImplementedException();
        }

        private void CardReaderOnCardInvalid(object sender, EventArgs eventArgs)
        {
            //if (assign != null) return;
            ////log.WriteMessage("Invalid Card");
            //ShowBad("Das ist keine Bierkarte, Junge!");
            //playSound("error.wav");
            //_resetTimer.Start(); 
        }

        private void CardReaderOnCardRead(object sender, CardReadEventArgs e)
        {
            LogWriter.Write(_drink.ToString(), LogWriter.LogLevel.Status, this);
            _checkIn.ShowNeutral("Warten...");
#if !DEBUG   
            LogWriter.Write("Cardreader: " + e.CardIdentity, LogWriter.LogLevel.Status, this); 
#endif
            if (_checkIn.AssignMode())
            {
                AssignUserToCard(e.CardIdentity);
                if(!SuggestionOverideAssignment) _checkIn.FinalizeAssignCard();
                ResetTimer();
                return;
            }

            _currentUser = _backend.GetUserByCardId(e.CardIdentity);
            
            int cardType = _backend.GetCardType(e.CardIdentity);
            

            if (_guestAssignMode)
            {
                _backend.AssignUserToCard(_currentUser, _overwriteCardId);
                _backend.SetCardType(2, _overwriteCardId);
                ResetTimer();
                _checkIn.SetStatusContentLabel("Gastkarte wird gebucht auf " + _currentUser + ". Schönen Schmidtwoch.");
                _guestAssignMode = false;
                return;
            }

            if (_gameCdPlayingMode && _currentUser == _currentGameCdPlayer) GameCdPlayerWon();

            _overwriteCardId = e.CardIdentity;

            if(cardType == 3) // nicht zugewiesene Gastkarte
            {
                _guestAssignMode = true;
                _checkIn.ShowNeutral("Gastkarte nicht zugewiesen. Bitte Gönner suchen. Der soll seine dann duchziehen.");
                _cardReader.AcceptNextCard();
                return;
            }
                

            if (_currentUser == null)
            {
                _checkIn.ShowBad("Karte nicht zugewiesen!");
                ResetTimer();
                return;
            }
            _backend.GetLastTransaction(_currentUser);


            if (!InviteMode)
            {
                if(cardType == 2) // Gastkarte
                {
                    _backend.WriteTransaction(_guestUser, 2, _drink);
                    _backend.WriteTransaction(_currentUser, 3, _drink);
                }
                else // Keine Gastkarte
                {
                    _backend.WriteTransaction(_currentUser, _transactionType, _drink);
                }
                
                
#if DEBUG
                if (Properties.Settings.Default.WebConnectorStatus)
                {
                    _webConnector.SendTransaction(_currentUser);
                }
                ChangeDrink(Drink.Beer);
#endif
            }

#region InviterMode
                
            else
            {
                
                if (_transactionType == 3)
                {
                    _inviterUser = _currentUser;
                    _checkIn.SetInviterImage(_uriConnector.GetProfileImage(_currentUser));
                    _checkIn.SetStatusContentLabel("Begünstigter, ziehen Sie durch.");
                    _transactionType--;
                    goto FinalizeTansaction;

                }
                _inviterList.Add(_currentUser);
                //_backend.WriteTransaction(_currentUser, _transactionType, _drink);
                foreach (var user in _inviterList)
                {
                    LogWriter.Write("InviterList: " + user, LogWriter.LogLevel.Status, this);
                }

            }


            if (_transactionType == 2)
            {
                try
                {
                    _checkIn.AddInvitedUserImage(_uriConnector.GetProfileImage(_currentUser));

                }
                catch
                {
                    //todo log schreiben
                }
                
            }
#endregion

            _backend.IncreaseBarrel();

            FinalizeTansaction:

            // Transaktion abschließen
            //todo rename und pfade verschieben
            _checkIn.UpdateLiquidity(_backend.CheckLiquidity(_currentUser));
            if (_currentUser.SoundType != null)
                _uriConnector.PlayLiquiditySound(_backend.CheckLiquidity(_currentUser), (int)_currentUser.SoundType);
            else _uriConnector.PlayLiquiditySound(_backend.CheckLiquidity(_currentUser), 1);

            _checkIn.statusContentLabel.Content = cardType ==1 ? (String.Format("Danke {0}, dein Vorgang wurde aufgenommen.", _currentUser.FirstName)) 
                : (String.Format("Danke {0}, dass Du den Gast eingeladen hast.", _currentUser.FirstName));

            //User zum GameCountdown hinzufügen
            if (Properties.Settings.Default.GameCdEnabled)
            {
                if (_initGameCd == null)
                {
                    _initGameCd = OnGameStart;
                    _startGameCd = OnGameDrink;
                    _lostGameCdEventHandler = GameCdPlayerLost;
                    GameCountdown.Instance.GameCdStart += _initGameCd;
                    GameCountdown.Instance.GameCdDrink += _startGameCd;
                    GameCdTab.Instance.GameLost += GameCdPlayerLost;

                }
                GameCountdown.Instance.AddToList(_currentUser.ID);
            }
            UpdateUserFromWeb(_currentUser);
            ResetTimer();
            UpdateStats();

        }
        
        private void ResetTimer()
        {
            _cardTimer.Start();
        }

        internal void BarrelReset()
        {
            _backend.ResetBarrel();
            UpdateStats();
        }

        public void OpenCheckIn()
        {
            _checkIn = CheckIn.Instance;
            KeyManager.Init();
            _checkIn.Show();
            _checkIn.ShowNeutral("Initialize...");
            UpdateStats();
            //Gastkarte initialisieren
            _guestUser = _backend.GetUser(45);
            if(Ranking.IsNotToday(_backend.GetLastTransaction().Timestamp))
            {
                _backend.ResetGuestCards();
            }

            _checkIn.ShowGood("Bereit");
            _beerboxUpdater = new BeerboxUpdater(_uriConnector, _backend);
            _beerboxUpdater.MessageFromBeerbox += _beerboxUpdater_MessageFromBeerbox;
            //BMS-Status an Webserver senden
            if (Properties.Settings.Default.WebConnectorStatus){ _webConnector.UpdateBmsStatus(1);}
            
        }
        
        internal void CloseCheckIn()
        {
            if (Properties.Settings.Default.WebConnectorStatus) _webConnector.UpdateBmsStatus(0);
            Properties.Settings.Default.Save();
            _checkIn.Hide();
        }

        public void CloseCurrentTab()
        {
            _checkIn.DeleteSelectedTabItem();
        }

        public void ToggleBeerDoctor()
        {
            if (Equals(_checkIn.BeerDocterRectangle.Stroke, Brushes.Red))
            {
                _checkIn.BeerDocterRectangle.Stroke = Brushes.Transparent;
                _docterNumber = 0;
            }
            else
            {
                _checkIn.BeerDocterRectangle.Stroke = Brushes.Red;
            }
            
        }

        internal void ToggleBeerDoctor(string direction)
        {
            if (direction.ToLower().Equals("left"))
            {
                if (_backend.GetBeerDocterCount() - 1 > _docterNumber)
                    _docterNumber++;
                // BeerDocter akutalisieren
                _beerdocterProfile = new BeerdocterProfile(_backend.GetBeerDocterProfile(_docterNumber))
                    {
                        BitmapImage = _uriConnector.GetProfileImage(_backend.GetBeerDocterProfile(_docterNumber))
                    };
                _checkIn.UpdateBeerDocterProfile(_beerdocterProfile);
               
            }
            if (direction.ToLower().Equals("right"))
            {
                if (_docterNumber > 0)
                    _docterNumber--;
                // BeerDocter akutalisieren
                _beerdocterProfile = new BeerdocterProfile(_backend.GetBeerDocterProfile(_docterNumber))
                    {
                        BitmapImage = _uriConnector.GetProfileImage(_backend.GetBeerDocterProfile(_docterNumber))
                    };
                _checkIn.UpdateBeerDocterProfile(_beerdocterProfile);
            }
        }

        public void ResetLastTransaction()
        {
            _backend.DeleteLastTransaction();
            _currentUser = _backend.GetCurrentUser();
            UpdateStats();
        }

        public void StartInviteMode()
        {
            EnableInviterMode();
        }

        public void EnterBeerBox()
        {
            if(!_checkIn.BeerboxIsOpen)_checkIn.ToggleBeerbox();
            _checkIn.BeerBoxWrite();
            _checkIn.BeerboxWriteMode = true;
        }

        public void EnterGamesMode()
        {
            throw new NotImplementedException();
        }

        public void ShowLog()
        {
            _checkIn.CreateLogForm(_uriConnector.ReadLogfile());
        }

        public void ChangeDrink(Drink drink)
        {
            _drink = drink;
            _checkIn.SetStatusContentLabel("Bitte ziehen Sie durch");
            _checkIn.SetStatusLabel(_drink.ToString() + "mode:");
        }

        void _beerboxUpdater_MessageFromBeerbox(object sender, BeerboxEventArgs e)
        {
            _checkIn.AddItemToBeerbox(e.Item);
        }

        public void WriteBeerbill(DateTime date)
        {
            _backend.ManagingBeerbillAccount(date);
                        
        }

        public void UpdateUserAccountBeerbill()
        {
            try
            {
                var thread = new Thread(() => _backend.Missmach());
                thread.Start();
              
            }
            catch (Exception ex)
            {
                LogWriter.Write("UpdateUserAccountBeerbill: " + ex.StackTrace + ex.Message, LogWriter.LogLevel.Error, this);
                MessageBox.Show("Fehlbetrag nicht erfolgreich aktualisiert! Siehe Logdatei");
            }
            
        }

        
        public void TestMethod()
        {
            _checkIn.ToggleBeerbox();
        }

        public void TestMethod2()
        {
            User u = _backend.GetUser(3);
            u.Beer_total = 10000;

            UpdateUserFromWeb(u);
        }

        private void UpdateUserFromWeb(User u)
        {
            if (Properties.Settings.Default.WebConnectorStatus)
            {
                u = _webConnector.GetUserInfo(u);
                if (u != null)
                {
                    _backend.UpdateUser(u);
                    if (u.ImagePath != null) _uriConnector.DownloadImage(u);
                }
            }
        }

        public void EnterAssignUserCard()
        {
            _checkIn.ShowAssignCard(GetUserNames());

        }

        private string[] GetUserNames()
        {
            return _backend.GetUserNames();
        }
        
        public void AssignUserToCard(int cardId)
        {
            if (_backend.GetUserByCardId(cardId)!=null)
            {
                SuggestionOverideAssignment = true;
                _overwriteCardId = cardId;
                _checkIn.AssigningOverwrite(_backend.GetUserByCardId(cardId).FirstName + " " 
                    + _backend.GetUserByCardId(cardId).LastName);
            }
            else
            {
                AssigningUserToCard(cardId);
                
            }
            
        }
        public void AssigningUserToCard()
        {
            SuggestionOverideAssignment = false;
            _backend.AssignUserToCard(_checkIn.GetAssigningName(), _overwriteCardId);
            _checkIn.FinalizeAssignCard();
        }

        public void AssigningUserToCard(int cardId)
        {
            
            _backend.AssignUserToCard(_checkIn.GetAssigningName(), cardId);
        }


        public void CreateUser()
        {
            _backend.CreateUser(_checkIn.GetAssigningName());
            _checkIn.StartAssigning();
            SuggestionCreateUser = false;

        }

        public void QuestionUserExists()
        {
            if (_backend.QuestionUserExists(_checkIn.GetAssigningName())) _checkIn.StartAssigning();
            else if (_checkIn.GetAssigningName()!= "")
            {
                _checkIn.DeactivateCombobox();
                _checkIn.SuggestCreateUser();
                SuggestionCreateUser = true;
            }
            else _checkIn.SetStatusContentLabel("Feld Name darf nicht leer sein.");
        }

        public void GuestCardSwipe(int i)
        {
            CardReaderOnCardRead(_cardReader, new CardReadEventArgs(i));
        }

        public void UpdateWebUsers()
        {
            _webConnector.UpdateWebProfiles(_backend.GetAllUsers());
        }

        public void SetWebStatus(int b)
        {
            if (Properties.Settings.Default.WebConnectorStatus)
            {
                _webConnector.UpdateBmsStatus(b);
            }
        }


        public void InitializeEmulatedCardReader()
        {
            _cardReader.CardRead -= CardReaderOnCardRead;
            _cardReader = new EmulatedCardReader();
            _cardReader.CardRead += CardReaderOnCardRead;
            _cardReader.AcceptNextCard();
        }

        public void SendBeerboxMessage()
        {
            // Send Message To schmidtwoch.com
            _checkIn.BeerboxWriteMode = false;
            if (_checkIn.beerBox.SelectedItem != null)
            {
                MessageBox.Show(_checkIn.BeerBoxInputTextBox.Text + "Comment:"
                                +
                                _webConnector.ToUnixTimespan(
                                    _checkIn.GetTimestampFromListBoxItem((BeerboxItem) _checkIn.beerBox.SelectedItem)));
            }
            else
            {
                MessageBox.Show(_checkIn.BeerBoxInputTextBox.Text);
            }
            
            _checkIn.BeerBoxInputTextBox.Text = "";
            if (_checkIn.beerBox.Items.Count != 0) _checkIn.BeerBoxGetFocus();
        }

        public void Dispose()
        {
            _checkIn = null;
            if (_beerboxUpdater != null) _beerboxUpdater.Close();
        }


        private void OnGameStart(object sender, EventArgs args)
        {
            _uriConnector.PlayGameSound(UriConnector.GameCdSound.Inititate);
        }

        private void OnGameDrink(object sender, GameCdEventArgs args)
        {
            User player = _backend.GetUser(args.PlayerId);
            _userProfile = new UserProfile(player)
            {
                BitmapImage = _uriConnector.GetProfileImage(player),
            };
            _currentGameCdPlayer = player;

            var expTime = (DateTime.Now - _currentGameCdPlayer.LastTransaction_Datetime).Value.Minutes;
            var rnd = new Random(DateTime.Now.Millisecond);
            var rndTime = 40 - rnd.Next(expTime)*30/45;
            _checkIn.InitializeGameCd(_userProfile, rndTime);


            //Setzt den Spielmodus auf Player spielt;Countdown läuft
            _gameCdPlayingMode = true;
            _uriConnector.PlayGameSound(UriConnector.GameCdSound.Countdown);
           
        }

        private void GameCdPlayerWon()
        {
            _backend.GameCdWon(_currentGameCdPlayer, 1);
            _checkIn.FinalizeGameCd();
            _gameCdPlayingMode = false;
            GameCdTab.Instance.StopCountdowntimer();
            _uriConnector.PlayGameSound(UriConnector.GameCdSound.Won);
            GameCountdown.Instance.InitiateNewGame();
        }

        public void GameCdPlayerLost(object sender, EventArgs args)
        {
            UriConnector.Instance.StopPlaying();
            _gameCdPlayingMode = false;
            UriConnector.Instance.PlayGameSound(UriConnector.GameCdSound.Lost);
            CheckIn.Instance.FinalizeGameCd();
            GameCountdown.Instance.InitiateNewGame();
        }


    }
}
